#pragma once
#include <iostream>
#include <string>
#include <unistd.h>
#include <memory>
#include <sys/epoll.h>
#include <cerrno>
#include "Socket.hpp"
#include "nocopy.hpp"
#include "Epoller.hpp"
#include "Log.hpp"


// epoll_ctl 的最后一个参数
uint32_t EVENT_IN = EPOLLIN;    // 读事件
uint32_t EVENT_OUT = EPOLLOUT;  // 写事件

class EpollServer : public nocopy // 将服务器设置为禁止拷贝
{
    static const int num = 64; // epoll_create 的参数
public:
    EpollServer(uint16_t port = 8080) 
        :_port(port),
        _listensocket_ptr(new Sock()),
        _epoller_ptr(new Epoller())
    {}

    // 初始化服务器
    void Init() 
    {
        _listensocket_ptr->Socket();
        _listensocket_ptr->Bind(_port);
        _listensocket_ptr->Listen();

        lg(Info, "create listen socket success: %d", _listensocket_ptr->Fd());
    }

    // 链接操作
    void Accepter()
    {
        std::string clientip;
        uint16_t clientport;
        int sock = _listensocket_ptr->Accept(&clientip, &clientport);
        if (sock > 0)
        {
            // 我们不能直接读取
            _epoller_ptr->EpollerUpdate(EPOLL_CTL_ADD, sock, EVENT_IN);
            lg(Info, "get a new link, client info: %s:%d", clientip.c_str(), clientport);
            sleep(5);
        }
        
    }

    // 读取操作
    void Recver(int fd)
    {   
        while (true)
        {
            char buffer[1024];
            ssize_t n = read(fd, buffer, sizeof(buffer) - 1); // bug?
            if (n > 0)
            {
                buffer[n] = 0;
                std::cout << "get a messge: " << buffer << std::endl;
                
                // write
                std::string echo_str = "server echo: ";
                echo_str += buffer;
                write(fd, echo_str.c_str(), echo_str.size());
            }
            else if (n == 0)
            {
                lg(Info, "client quit, me too, close fd is: %d", fd);
                // 先从 epoll 模型中移除，再 close 
                _epoller_ptr->EpollerUpdate(EPOLL_CTL_DEL, fd, 0);
                close(fd);
            }
            else
            {
                lg(Warning, "recv error: fd is: %d", fd);
                _epoller_ptr->EpollerUpdate(EPOLL_CTL_DEL, fd, 0);
                close(fd);
            }

            sleep(1);
        }
        
    }

    // 根据事件类型(如读就绪、写就绪等)执行相应的操作, 即 分派器(调度器)
    void Dispatcher(struct epoll_event revs[], int num)
    {
        // 读取 revs 中的所有事件与 fd
        for(int i = 0; i < num; i++)
        {
            uint32_t events = revs[i].events;
            int fd = revs[i].data.fd;
            if (events & EVENT_IN) // 对读事件的处理
            {
                if (fd == _listensocket_ptr->Fd())
                {
                    //获取了一个新连接
                    Accepter();
                }
                else
                {
                    //其他fd上面的普通读取事件就绪
                    Recver(fd);
                }
            }
            else if (events & EVENT_OUT) // 对写事件的处理
            {

            }
            else // 对其他事件的处理
            {

            }
        }
    }

    void Start() 
    {
        // 将 listensock 添加到 epoll 中 -> 将 listensock 和他关心的事件，添加到内核 epoll 模型的 rb_tree 中
        _epoller_ptr->EpollerUpdate(EPOLL_CTL_ADD, _listensocket_ptr->Fd(), EVENT_IN);
        struct epoll_event revs[num];
        for (;;)
        {
            int n = _epoller_ptr->EpollerWait(revs, num);
            if (n > 0) // 有事件就绪
            {
                lg(Debug, "event happend, fd is: %d", revs[0].data.fd);

                Dispatcher(revs, num);
            }
            else if (n == 0)
            {
                lg(Info, "time out...");
            }
            else
            {
                lg(Error, "epoll wait error!");
            }
        }
    }

    ~EpollServer() 
    {
        _listensocket_ptr->Close();
    }
private:
    std::shared_ptr<Sock> _listensocket_ptr; // 监听套接字
    std::shared_ptr<Epoller> _epoller_ptr;   // epoll 句柄
    uint16_t _port;                          // 端口号
};
